import os
import shutil
import click
import json
import configparser
import hashlib
def create_file(file):
    open(file, "w+")
def write_file(file, content):
    with open(file, "w+") as f:
        f.write(content)
def file_append(file, content):
    with open(file, "a+") as f:
        f.write(content)
def read_file(file):
    with open(file, "r") as f:
        return f.readlines()[len(f.readlines()) - 1]
def countline(file_path, encoding='utf-8'):
    """
    使用readlines()统计文件行数
    
    参数:
        file_path (str): 文件路径
        encoding (str): 文件编码格式，默认为'utf-8'
        
    返回:
        int: 成功时返回文件行数，失败时返回-1
    """
    try:
        with open(file_path, 'r', encoding=encoding) as file:
            lines = file.readlines()  # 一次性读取所有行到列表
            return len(lines)         # 返回列表长度即为行数
            
    except FileNotFoundError:
        print(f"错误: 文件 '{file_path}' 不存在")
        return -1
    except PermissionError:
        print(f"错误: 没有读取文件 '{file_path}' 的权限")
        return -1
    except UnicodeDecodeError:
        print(f"错误: 文件 '{file_path}' 编码不是 {encoding}")
        return -1
    except Exception as e:
        print(f"读取文件时发生错误: {str(e)}")
        return -1
def string_to_md5(input_string, encoding='utf-8'):
    """
    计算字符串的MD5哈希值
    :param input_string: 输入字符串
    :param encoding: 字符串编码方式，默认utf-8
    :return: 32位十六进制MD5字符串
    """
    md5_hash = hashlib.md5()
    md5_hash.update(input_string.encode(encoding))
    return md5_hash.hexdigest()
@click.command()
@click.option('-i', '--init-base', help='创建一个基础仓库', is_flag=True)
@click.option('-a', '--cache-add', help='添加目录到暂存区')
@click.option('-s', '--sync', help='提交暂存区到当前树，必须有一个commit head', is_flag=True)
@click.option('-n', '--new-tree', help='创建一个新树，并进入')
@click.option('-S', '--switch-tree', help='切换到特定树')
@click.option('-r', '--restore', help='将当前树还原回指定目录')
@click.option('-d', '--delete-tree', help='删除当前树')
@click.option('-C', '--current', help='查看当前树下所有提交', is_flag=True)
@click.option('-m', '--merge', help='合并两个树，需指定-ms和-mt', is_flag=True)
@click.option('-ms', '--merge-tree-source', help='合并源树')
@click.option('-mt', '--merge-tree-target', help='合并目标树')
@click.option('-ch', "--commit-head", help='指定提交头')
@click.option('-e', '--extract', help='导出指定提交头提交文件到目录')
@click.option('-et', '--extract-to', help='指定导出目录')
def main(init_base, cache_add, sync, new_tree, switch_tree, restore, delete_tree, current, merge, merge_tree_source, merge_tree_target, commit_head, extract, extract_to):
    if init_base:
        if os.path.exists(".repo"):
            click.secho("已存在仓库", fg="red")
            return
        else:
            click.secho("创建仓库")
            os.mkdir(".repo")
            os.chdir(".repo")
            create_file(".sync")
            create_file(".tree")
            write_file(".current_tree", "master")
            os.mkdir("tree")
            os.mkdir("tree/master")
            create_file("tree/master/.config")
            os.mkdir("tree/master/files")
            os.mkdir("tree/master/cache_area/")
            create_file(".commit")
            create_file("tree/master/.latest")
            return
    if new_tree:
        if not os.path.exists(".repo"):
            click.secho("不存在仓库", fg="red")
            return
        if os.path.exists(f".repo/tree/{new_tree}"):
            click.secho("树已存在", fg="red")
            return
        os.mkdir(f".repo/tree/{new_tree}")
        create_file(f".repo/tree/{new_tree}/.config")
        write_file(".repo/.current_tree", new_tree)
        os.mkdir(f".repo/tree/{new_tree}/files")
        create_file(f".repo/tree/{new_tree}/.latest")
        os.mkdir(f".repo/tree/{new_tree}/cache_area")
        click.secho("创建完成")
    if switch_tree:
        if not os.path.exists(".repo"):
            click.secho("不存在仓库", fg="red")
            return
        if not os.path.exists(f".repo/tree/{switch_tree}"):
            click.secho("不存在那个树", fg="red")
            return
        write_file(".repo/.current_tree", switch_tree)
    if cache_add:
        if not os.path.exists(".repo"):
            click.secho("不存在仓库", fg="red")
            return
        current_tree = read_file(".repo/.current_tree")
        if not current_tree:
            click.secho("请先创建一个树", fg="red")
            return
        shutil.rmtree(f".repo/tree/{current_tree}/cache_area")
        os.mkdir(f".repo/tree/{current_tree}/cache_area")
        shutil.copytree(cache_add, f".repo/tree/{current_tree}/cache_area", dirs_exist_ok=True)
        click.secho("添加完成")
    if sync:
        if not os.path.exists(".repo"):
            click.secho("不存在仓库", fg="red")
            return
        current_tree = read_file(".repo/.current_tree")
        if not current_tree:
            click.secho("请先创建一个树", fg="red")
            return
        if not commit_head:
            click.secho("请输入提交信息", fg="red")
            return
        with open(".repo/.commit", "r+") as f:
            for i in f.readlines():
                if commit_head == i.split("$")[0]:
                    click.secho("不能有相同的提交头", fg="red")
                    return
        commit_id = countline(".repo/.commit") + 1
        md5 = string_to_md5(str(commit_head))
        file_append(f".repo/.commit", f"{commit_head}${current_tree}${commit_id}${md5}\n")
        write_file(f".repo/tree/{current_tree}/.latest", md5)
        shutil.copytree(f".repo/tree/{current_tree}/cache_area", f".repo/tree/{current_tree}/files/{md5}", dirs_exist_ok=True)
        shutil.rmtree(f".repo/tree/{current_tree}/cache_area")
        os.mkdir(f".repo/tree/{current_tree}/cache_area")
        click.secho("同步完成")
    if restore:
        if not os.path.exists(restore):
            click.secho("不存在目录", fg="red")
            return

        if not os.path.exists(".repo"):
            click.secho("不存在仓库", fg="red")
            return
        current_tree = read_file(".repo/.current_tree")
        if not current_tree:
            click.secho("请先创建一个树", fg="red")
            return
        if len(os.listdir(f".repo/tree/{current_tree}/files")) == 0:
            click.secho("当前树没有提交", fg="red")
            return
        commit = read_file(f".repo/tree/{current_tree}/.latest")
        shutil.copytree(f".repo/tree/{current_tree}/files/{commit}", restore, dirs_exist_ok=True)
        click.secho("还原完成")
    if delete_tree:
        if not os.path.exists(".repo"):
            click.secho("不存在仓库", fg="red")
            return
        if delete_tree == "master":
            click.secho("不能删除主树", fg="red")
            return
        if read_file(".repo/.current_tree") == delete_tree:
            click.secho("请先切换到其他树", fg="red")
            return
        if not os.path.exists(f".repo/tree/{delete_tree}"):
            click.secho("不存在那个树", fg="red")
        else:
            shutil.rmtree(f".repo/tree/{delete_tree}")
            click.secho("删除完成")
    if current:
        if not os.path.exists(".repo"):
            click.secho("不存在仓库", fg="red")
            return
        current_tree = read_file(".repo/.current_tree")
        if not current_tree:
            click.secho("请先创建一个树", fg="red")
            return
        for file in os.listdir(f".repo/tree/{current_tree}/files"):
            click.secho(file, fg="green")
    if merge_tree_source and merge_tree_target and merge:
        if not os.path.exists(".repo"):
            click.secho("不存在仓库", fg="red")
            return
        current_tree = read_file(".repo/.current_tree")
        for i in os.listdir(f".repo/tree/{merge_tree_target}"):
            if i in os.listdir(f".repo/tree/{merge_tree_source}"):
                click.secho(f"reject {merge_tree_source} -> {merge_tree_target}", fg="red")
                click.secho(f"commit {i} is already exist in tree {merge_tree_source}", fg="red")
                return
        if current_tree == merge_tree_source:
            click.secho("当前树不能为源树", fg="red")
            return
        if merge_tree_source == "master":
            click.secho("主树不能作为源树", fg="red")
            return
        shutil.copytree(f".repo/tree/{merge_tree_source}/files", f".repo/tree/{merge_tree_target}/files", dirs_exist_ok=True)
        shutil.rmtree(f".repo/tree/{merge_tree_source}")
        click.secho("合并完成")
    if extract:
        if not extract_to:
            click.secho("请指定提取目录", fg="red")
            return
        current_tree = read_file(".repo/.current_tree")
        extractmd5 = string_to_md5(extract)
        if not os.path.exists(f".repo/tree/{current_tree}/files/{extractmd5}"):
            click.secho("未找到此文件", fg="red")
            return
        shutil.copytree(f".repo/tree/{current_tree}/files/{extractmd5}", f"{extract_to}", dirs_exist_ok=True)




if __name__ == "__main__":
    main()